/**
 * Ymodem协议简化版 - 基于C++实现
 * 参考：DunenConfigerPhoneQT6/3rdParty/SerialPortYmodem-master/SerialPortYmodem/Ymodem.cpp
 */

// Ymodem协议常量
const SOH = 0x01;  // 128字节数据包
const STX = 0x02;  // 1K字节数据包
const EOT = 0x04;  // 传输结束
const ACK = 0x06;  // 确认
const NAK = 0x15;  // 否定应答
const CAN = 0x18;  // 取消传输
const CRC = 0x43;  // 'C' - CRC模式

class YmodemSimple {
  constructor() {
    this.packetSize = 128;  // 使用128字节包（更稳定）
    this.maxRetry = 10;
    this.txBuffer = null;    // 保存当前发送的数据包，用于重发
    this.txLength = 0;
  }

  /**
   * CRC16计算 - 与C++版本完全一致
   */
  crc16(data) {
    let crc = 0;
    for (let i = 0; i < data.length; i++) {
      crc = crc ^ (data[i] << 8);
      for (let j = 0; j < 8; j++) {
        if (crc & 0x8000) {
          crc = (crc << 1) ^ 0x1021;
        } else {
          crc = crc << 1;
        }
      }
    }
    return crc & 0xFFFF;
  }

  /**
   * 构建数据包
   * @param {number} seq - 序列号
   * @param {Uint8Array} data - 数据（128或1024字节）
   * @param {boolean} use1K - 是否使用1K包
   */
  buildPacket(seq, data, use1K = true) {
    const dataSize = use1K ? 1024 : 128;
    const header = use1K ? STX : SOH;
    
    // 创建数据包缓冲区
    const packet = new Uint8Array(dataSize + 5); // header(1) + seq(1) + ~seq(1) + data(n) + crc(2)
    
    packet[0] = header;
    packet[1] = seq & 0xFF;
    packet[2] = (0xFF - seq) & 0xFF;  // 反码
    
    // 填充数据（使用0xFF填充，与C++的YMODEM_PACKET_CPMEOF一致）
    for (let i = 0; i < dataSize; i++) {
      packet[3 + i] = i < data.length ? data[i] : 0xFF;
    }
    
    // 计算并添加CRC
    const crc = this.crc16(packet.slice(3, 3 + dataSize));
    packet[3 + dataSize] = (crc >> 8) & 0xFF;
    packet[4 + dataSize] = crc & 0xFF;
    
    console.log('[Ymodem] 构建数据包: header=0x' + header.toString(16) + 
                ', seq=' + seq + ', ~seq=' + packet[2] + 
                ', dataSize=' + dataSize + ', CRC=0x' + crc.toString(16) +
                ', 总长度=' + packet.length);
    console.log('[Ymodem] 数据包详情: 前20字节:', Array.from(packet.slice(0, 20)));
    console.log('[Ymodem] 数据包详情: 后10字节:', Array.from(packet.slice(packet.length - 10)));
    
    return packet;
  }

  /**
   * 构建文件信息包（Packet 0）
   */
  buildFileInfoPacket(filename, filesize) {
    const data = new Uint8Array(128);
    let offset = 0;
    
    // 文件名（以NULL结尾）
    for (let i = 0; i < filename.length && i < 127; i++) {
      data[offset++] = filename.charCodeAt(i);
    }
    data[offset++] = 0; // NULL终止符
    
    // 文件大小（ASCII字符串）
    const sizeStr = filesize.toString();
    for (let i = 0; i < sizeStr.length && offset < 127; i++) {
      data[offset++] = sizeStr.charCodeAt(i);
    }
    data[offset++] = 0; // NULL终止符
    
    // 其余部分填充0（文件信息包用NULL填充，与C++一致）
    for (let i = offset; i < 128; i++) {
      data[i] = 0;
    }
    
    return this.buildPacket(0, data, false); // 文件信息包使用128字节
  }

  /**
   * 等待特定字符（参考C++的transmitStageEstablishing逻辑）
   */
  async waitForSignal(readFunc, expected, timeout = 10000) {
    console.log('[Ymodem] 等待信号:', expected.toString(16));
    const startTime = Date.now();
    
    while (Date.now() - startTime < timeout) {
      const data = await readFunc(false); // 不清空队列
      
      if (data && data.length > 0) {
        console.log('[Ymodem] waitForSignal收到数据:', Array.from(data));
        
        // 在数据中查找期望的字符
        for (let i = 0; i < data.length; i++) {
          if (data[i] === expected) {
            console.log('[Ymodem] ✓ 找到期望字符:', expected.toString(16));
            // ✅ 清空队列
            await readFunc(true);
            return true;
          }
          // 检查中止信号（连续的CAN）
          if (data[i] === CAN) {
            let canCount = 1;
            for (let j = i + 1; j < data.length && j < i + 3; j++) {
              if (data[j] === CAN) canCount++;
            }
            if (canCount >= 2) {
              console.error('[Ymodem] 收到中止信号(CAN)');
              throw new Error('传输被中止');
            }
          }
        }
      }
      
      await new Promise(resolve => setTimeout(resolve, 100));
    }
    
    throw new Error('等待信号超时: ' + expected.toString(16));
  }

  /**
   * 发送数据包并等待ACK（带超时重发，参考C++的transmitStageTransmitting）
   */
  async sendPacketWithRetry(packet, writeFunc, readFunc, seq, maxRetry = 10) {
    console.log('[Ymodem] 发送数据包，序列号:', seq, '长度:', packet.length);
    
    // 保存到txBuffer用于重发
    this.txBuffer = packet;
    this.txLength = packet.length;
    
    for (let retry = 0; retry < maxRetry; retry++) {
      if (retry > 0) {
        console.log('[Ymodem] 重发数据包，序列号:', seq, '重试:', retry);
      }
      
      // 发送数据包
      await writeFunc(this.txBuffer);
      
      // ✅ 发送完成后，先等待一段时间让控制器处理
      // 控制器需要时间：接收BLE分包 → 重组 → 计算CRC → 验证 → 发送ACK
      console.log('[Ymodem] 等待控制器处理数据包...');
      await new Promise(resolve => setTimeout(resolve, 300));
      
      // 等待响应（带超时）
      const startTime = Date.now();
      const responseTimeout = 5000; // 5秒超时
      let checkCount = 0;
      
      while (Date.now() - startTime < responseTimeout) {
        checkCount++;
        const data = await readFunc(false); // 不清空队列
        
        if (data && data.length > 0) {
          console.log('[Ymodem] 第' + checkCount + '次检查，收到响应(长度=' + data.length + '):', Array.from(data));
          console.log('[Ymodem] 响应数据HEX:', Array.from(data).map(b => '0x' + b.toString(16).toUpperCase().padStart(2, '0')).join(' '));
          
          // 检查是否包含ACK
          let hasAck = false;
          let hasNak = false;
          let hasCan = false;
          for (let i = 0; i < data.length; i++) {
            if (data[i] === ACK) hasAck = true;
            if (data[i] === NAK) hasNak = true;
            if (data[i] === CAN) hasCan = true;
          }
          console.log('[Ymodem] 响应分析: ACK=' + hasAck + ', NAK=' + hasNak + ', CAN=' + hasCan);
          
          for (let i = 0; i < data.length; i++) {
            // 收到ACK，成功
            if (data[i] === ACK) {
              console.log('[Ymodem] ✓ 收到ACK (位置:', i, ')');
              // ✅ 清空队列
              await readFunc(true);
              return true;
            }
            
            // 收到NAK，重发
            if (data[i] === NAK) {
              console.warn('[Ymodem] ✗ 收到NAK，准备重发...');
              // ✅ 清空队列
              await readFunc(true);
              await new Promise(resolve => setTimeout(resolve, 200));
              break; // 跳出内层循环，进入重试
            }
            
            // 收到C，也视为需要重发
            if (data[i] === CRC) {
              console.log('[Ymodem] 收到C，准备重发...');
              // ✅ 清空队列
              await readFunc(true);
              await new Promise(resolve => setTimeout(resolve, 200));
              break;
            }
            
            // 检查中止信号
            if (data[i] === CAN) {
              let canCount = 1;
              for (let j = i + 1; j < data.length && j < i + 3; j++) {
                if (data[j] === CAN) canCount++;
              }
              if (canCount >= 2) {
                throw new Error('传输被中止(收到多个CAN)');
              }
            }
          }
        }
        
        await new Promise(resolve => setTimeout(resolve, 100));
      }
      
      // 超时，重试（类似C++的timeout重发）
      console.warn('[Ymodem] ⏱ 等待ACK超时，准备重试...');
      await new Promise(resolve => setTimeout(resolve, 200));
    }
    
    throw new Error('发送数据包失败，超过最大重试次数: ' + seq);
  }

  /**
   * 发送EOT并等待ACK
   */
  async sendEOT(writeFunc, readFunc) {
    console.log('[Ymodem] 发送EOT');
    
    for (let retry = 0; retry < 10; retry++) {
      const eot = new Uint8Array([EOT]);
      await writeFunc(eot);
      
      // ✅ 发送完成后，先等待一段时间
      await new Promise(resolve => setTimeout(resolve, 100));
      
      const startTime = Date.now();
      while (Date.now() - startTime < 5000) {
        const data = await readFunc(false); // 不清空队列
        
        if (data && data.length > 0) {
          console.log('[Ymodem] EOT响应:', Array.from(data));
          
          for (let i = 0; i < data.length; i++) {
            if (data[i] === ACK) {
              console.log('[Ymodem] ✓ EOT收到ACK');
              // ✅ 清空队列
              await readFunc(true);
              return true;
            }
            if (data[i] === NAK) {
              console.log('[Ymodem] EOT收到NAK，重发...');
              // ✅ 清空队列
              await readFunc(true);
              break;
            }
          }
        }
        
        await new Promise(resolve => setTimeout(resolve, 100));
      }
      
      console.warn('[Ymodem] EOT超时，重试...');
    }
    
    throw new Error('发送EOT失败');
  }

  /**
   * 发送文件
   * 参考C++的状态机流程：
   * StageNone -> StageEstablishing -> StageEstablished -> StageTransmitting -> StageFinishing -> Finished
   */
  async sendFile(fileData, filename, writeFunc, readFunc, onProgress) {
    try {
      console.log('[Ymodem] 开始Ymodem传输');
      console.log('[Ymodem] 文件名:', filename);
      console.log('[Ymodem] 文件大小:', fileData.length, 'bytes');
      
      // ========== Stage 1: StageEstablishing - 等待'C'并发送文件信息包 ==========
      console.log('[Ymodem] ===== Stage 1: Establishing =====');
      await this.waitForSignal(readFunc, CRC, 10000);
      
      // 发送文件信息包（Packet 0）
      const fileInfoPacket = this.buildFileInfoPacket(filename, fileData.length);
      await this.sendPacketWithRetry(fileInfoPacket, writeFunc, readFunc, 0);
      
      // ========== Stage 2: StageEstablished - 等待'C'开始数据传输 ==========
      console.log('[Ymodem] ===== Stage 2: Established =====');
      await this.waitForSignal(readFunc, CRC, 10000);
      
      // ========== Stage 3: StageTransmitting - 发送数据包 ==========
      console.log('[Ymodem] ===== Stage 3: Transmitting =====');
      const totalPackets = Math.ceil(fileData.length / this.packetSize);
      let offset = 0;
      let seq = 1; // 从序列号1开始
      
      for (let i = 0; i < totalPackets; i++) {
        const chunk = fileData.slice(offset, offset + this.packetSize);
        const packet = this.buildPacket(seq & 0xFF, chunk, false); // 使用128字节包
        
        console.log(`[Ymodem] 发送数据包 ${i + 1}/${totalPackets}, 序列号: ${seq & 0xFF}`);
        await this.sendPacketWithRetry(packet, writeFunc, readFunc, seq & 0xFF);
        
        offset += this.packetSize;
        seq++;
        
        // 更新进度
        if (onProgress) {
          const progress = Math.min(100, Math.round((offset / fileData.length) * 100));
          onProgress(progress);
        }
      }
      
      // ========== Stage 4: StageFinishing - 发送EOT ==========
      console.log('[Ymodem] ===== Stage 4: Finishing =====');
      await this.sendEOT(writeFunc, readFunc);
      
      // ========== Stage 5: Finished - 等待最后的'C'并发送空包 ==========
      console.log('[Ymodem] ===== Stage 5: Finished =====');
      await this.waitForSignal(readFunc, CRC, 5000);
      
      // 发送空包结束会话（Packet 0，全NULL）
      const emptyData = new Uint8Array(128);
      for (let i = 0; i < 128; i++) {
        emptyData[i] = 0; // NULL填充
      }
      const emptyPacket = this.buildPacket(0, emptyData, false);
      await writeFunc(emptyPacket);
      
      // 等待最后的ACK
      const startTime = Date.now();
      while (Date.now() - startTime < 3000) {
        const data = await readFunc(false); // 不清空队列
        if (data && data.length > 0) {
          for (let i = 0; i < data.length; i++) {
            if (data[i] === ACK) {
              console.log('[Ymodem] ✓ 传输成功完成！');
              // ✅ 清空队列
              await readFunc(true);
              return true;
            }
          }
        }
        await new Promise(resolve => setTimeout(resolve, 100));
      }
      
      console.log('[Ymodem] ✓ 传输完成（未收到最后ACK，但可能成功）');
      return true;
      
    } catch (error) {
      console.error('[Ymodem] ✗ 传输失败:', error.message);
      throw error;
    }
  }
}

module.exports = YmodemSimple;
